home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / src / startup.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-04-02  |  29.1 KB  |  1,080 lines

  1. /*
  2.  *  Window Maker window manager
  3.  *
  4.  *  Copyright (c) 1997, 1998 Alfredo K. Kojima
  5.  *  Copyright (c) 1999       Dan Pascu
  6.  *
  7.  *  This program is free software; you can redistribute it and/or modify
  8.  *  it under the terms of the GNU General Public License as published by
  9.  *  the Free Software Foundation; either version 2 of the License, or
  10.  *  (at your option) any later version.
  11.  *
  12.  *  This program is distributed in the hope that it will be useful,
  13.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  *  GNU General Public License for more details.
  16.  *
  17.  *  You should have received a copy of the GNU General Public License
  18.  *  along with this program; if not, write to the Free Software
  19.  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 
  20.  *  USA.
  21.  */
  22.  
  23. #include "wconfig.h"
  24.  
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <unistd.h>
  28. #include <signal.h>
  29. #include <sys/wait.h>
  30. #ifdef __FreeBSD__
  31. #include <sys/signal.h>
  32. #endif
  33.  
  34. #include <X11/Xlib.h>
  35. #include <X11/Xutil.h>
  36. #include <X11/Intrinsic.h>
  37. #include <X11/cursorfont.h>
  38. #include <X11/Xproto.h>
  39. #include <X11/keysym.h>
  40. #ifdef SHAPE
  41. #include <X11/extensions/shape.h>
  42. #endif
  43.  
  44. #include "WindowMaker.h"
  45. #include "GNUstep.h"
  46. #include "texture.h"
  47. #include "screen.h"
  48. #include "window.h"
  49. #include "actions.h"
  50. #include "client.h"
  51. #include "funcs.h"
  52. #include "dock.h"
  53. #include "workspace.h"
  54. #include "keybind.h"
  55. #include "framewin.h"
  56. #include "session.h"
  57. #include "defaults.h"
  58. #include "properties.h"
  59. #include "dialog.h"
  60. #ifdef XDND
  61. #include "xdnd.h"
  62. #endif
  63.  
  64. #include "xutil.h"
  65.  
  66. #ifdef KWM_HINTS
  67. #include "kwm.h"
  68. #endif
  69.  
  70. #if 0
  71. #ifdef SYS_SIGLIST_DECLARED
  72. extern const char * const sys_siglist[];
  73. #endif
  74. #endif
  75.  
  76. /* for SunOS */
  77. #ifndef SA_RESTART
  78. # define SA_RESTART 0
  79. #endif
  80.  
  81.  
  82. /****** Global Variables ******/
  83.  
  84. extern WPreferences wPreferences;
  85.  
  86. extern WDDomain *WDWindowMaker;
  87. extern WDDomain *WDRootMenu;
  88. extern WDDomain *WDWindowAttributes;
  89.  
  90. extern WShortKey wKeyBindings[WKBD_LAST];
  91.  
  92. extern int wScreenCount;
  93.  
  94.  
  95. #ifdef SHAPE
  96. extern Bool wShapeSupported;
  97. extern int wShapeEventBase;
  98. #endif
  99.  
  100. #ifdef KEEP_XKB_LOCK_STATUS
  101. extern Bool wXkbSupported;
  102. extern int wXkbEventBase;
  103. #endif
  104.  
  105. /* contexts */
  106. extern XContext wWinContext;
  107. extern XContext wAppWinContext;
  108. extern XContext wStackContext;
  109.  
  110. /* atoms */
  111. extern Atom _XA_WM_STATE;
  112. extern Atom _XA_WM_CHANGE_STATE;
  113. extern Atom _XA_WM_PROTOCOLS;
  114. extern Atom _XA_WM_TAKE_FOCUS;
  115. extern Atom _XA_WM_DELETE_WINDOW;
  116. extern Atom _XA_WM_SAVE_YOURSELF;
  117. extern Atom _XA_WM_CLIENT_LEADER;
  118. extern Atom _XA_WM_COLORMAP_WINDOWS;
  119. extern Atom _XA_WM_COLORMAP_NOTIFY;
  120.  
  121. extern Atom _XA_GNUSTEP_WM_ATTR;
  122.  
  123. extern Atom _XA_WINDOWMAKER_MENU;
  124. extern Atom _XA_WINDOWMAKER_WM_PROTOCOLS;
  125. extern Atom _XA_WINDOWMAKER_STATE;
  126. extern Atom _XA_WINDOWMAKER_WM_FUNCTION;
  127. extern Atom _XA_WINDOWMAKER_NOTICEBOARD;
  128. extern Atom _XA_WINDOWMAKER_COMMAND;
  129. extern Atom _XA_WINDOWMAKER_ICON_SIZE;
  130. extern Atom _XA_WINDOWMAKER_ICON_TILE;
  131.  
  132. extern Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW;
  133. extern Atom _XA_GNUSTEP_TITLEBAR_STATE;
  134.  
  135. #ifdef OFFIX_DND
  136. extern Atom _XA_DND_PROTOCOL;
  137. extern Atom _XA_DND_SELECTION;
  138. #endif
  139.  
  140.  
  141. /* cursors */
  142. extern Cursor wCursor[WCUR_LAST];
  143.  
  144. /* special flags */
  145. extern char WDelayedActionSet;
  146.  
  147. /***** Local *****/
  148.  
  149. static WScreen **wScreen = NULL;
  150.  
  151.  
  152. static unsigned int _NumLockMask = 0;
  153. static unsigned int _ScrollLockMask = 0;
  154.  
  155.  
  156.  
  157. static void manageAllWindows();
  158.  
  159. extern void NotifyDeadProcess(pid_t pid, unsigned char status);
  160.  
  161.  
  162. static int 
  163. catchXError(Display *dpy, XErrorEvent *error)
  164. {
  165.     char buffer[MAXLINE];
  166.     
  167.     /* ignore some errors */
  168.     if (error->resourceid != None 
  169.     && ((error->error_code == BadDrawable 
  170.          && error->request_code == X_GetGeometry)
  171.         || (error->error_code == BadMatch
  172.         && (error->request_code == X_SetInputFocus))
  173.         || (error->error_code == BadWindow)
  174.         /*
  175.         && (error->request_code == X_GetWindowAttributes
  176.             || error->request_code == X_SetInputFocus
  177.             || error->request_code == X_ChangeWindowAttributes
  178.             || error->request_code == X_GetProperty
  179.             || error->request_code == X_ChangeProperty
  180.             || error->request_code == X_QueryTree
  181.             || error->request_code == X_GrabButton
  182.             || error->request_code == X_UngrabButton
  183.             || error->request_code == X_SendEvent
  184.             || error->request_code == X_ConfigureWindow))
  185.          */
  186.         || (error->request_code == X_InstallColormap))) {
  187. #ifndef DEBUG
  188.  
  189.     return 0;
  190. #else
  191.     printf("got X error %x %x %x\n", error->request_code,
  192.            error->error_code, (unsigned)error->resourceid);
  193.     return 0;
  194. #endif
  195.     }
  196.     FormatXError(dpy, error, buffer, MAXLINE);
  197.     wwarning(_("internal X error: %s\n"), buffer);
  198.     return -1;
  199. }
  200.  
  201.  
  202. /*
  203.  *---------------------------------------------------------------------- 
  204.  * handleXIO-
  205.  *     Handle X shutdowns and other stuff. 
  206.  *---------------------------------------------------------------------- 
  207.  */
  208. static int
  209. handleXIO(Display *xio_dpy)
  210. {
  211.     dpy = NULL;
  212.     Exit(0);
  213.     return 0;
  214. }
  215.  
  216.  
  217. /*
  218.  *----------------------------------------------------------------------
  219.  * delayedAction-
  220.  *     Action to be executed after the signal() handler is exited.
  221.  *----------------------------------------------------------------------
  222.  */
  223. static void
  224. delayedAction(void *cdata)
  225. {
  226.     WDelayedActionSet = 0;
  227.     /* 
  228.      * Make the event dispatcher do whatever it needs to do,
  229.      * including handling zombie processes, restart and exit 
  230.      * signals.
  231.      */
  232.     DispatchEvent(NULL);
  233. }
  234.  
  235.  
  236.  
  237. /*
  238.  *----------------------------------------------------------------------
  239.  * handleSig--
  240.  *     general signal handler. Exits the program gently.
  241.  *---------------------------------------------------------------------- 
  242.  */
  243. static RETSIGTYPE
  244. handleSig(int sig)
  245. {
  246.     static int already_crashed = 0;
  247.     int dumpcore = 0;
  248. #ifndef NO_EMERGENCY_AUTORESTART
  249.     int crashAction;
  250.     char *argv[2];
  251.     
  252.     argv[1] = NULL;
  253. #endif
  254.     
  255.     /* 
  256.      * No functions that potentially do Xlib calls should be called from
  257.      * here. Xlib calls are not reentrant so the integrity of Xlib is
  258.      * not guaranteed if a Xlib call is made from a signal handler.
  259.      */
  260.     if (sig == SIGUSR1) {
  261. #ifdef SYS_SIGLIST_DECLARED
  262.         wwarning(_("got signal %i (%s) - restarting\n"), sig, sys_siglist[sig]);
  263. #else
  264.         wwarning(_("got signal %i - restarting\n"), sig);
  265. #endif
  266.  
  267.     WCHANGE_STATE(WSTATE_NEED_RESTART);
  268.     /* setup idle handler, so that this will be handled when
  269.      * the select() is returned becaused of the signal, even if
  270.      * there are no X events in the queue */
  271.     if (!WDelayedActionSet) {
  272.         WDelayedActionSet = 1;
  273.         WMAddIdleHandler(delayedAction, NULL);
  274.     }
  275.         return;
  276.     } else if (sig == SIGTERM || sig == SIGHUP) {
  277. #ifdef SYS_SIGLIST_DECLARED
  278.         wwarning(_("got signal %i (%s) - exiting...\n"), sig, sys_siglist[sig]);
  279. #else
  280.         wwarning(_("got signal %i - exiting...\n"), sig);
  281. #endif
  282.  
  283.     WCHANGE_STATE(WSTATE_NEED_EXIT);
  284.  
  285.     if (!WDelayedActionSet) {
  286.         WDelayedActionSet = 1;
  287.         WMAddIdleHandler(delayedAction, NULL);
  288.     }
  289.     return;
  290.     }
  291.  
  292. #ifdef SYS_SIGLIST_DECLARED
  293.     wfatal(_("got signal %i (%s)\n"), sig, sys_siglist[sig]);
  294. #else
  295.     wfatal(_("got signal %i\n"), sig);
  296. #endif
  297.  
  298.     /* Setting the signal behaviour back to default and then reraising the
  299.      * signal is a cleaner way to make program exit and core dump than calling
  300.      * abort(), since it correctly returns from the signal handler and sets
  301.      * the flags accordingly. -Dan
  302.      */
  303.     if (sig==SIGSEGV || sig==SIGFPE || sig==SIGBUS || sig==SIGILL
  304.     || sig==SIGABRT) {
  305.     if (already_crashed) {
  306.         wfatal(_("crashed while trying to do some post-crash cleanup. Aborting immediatelly."));
  307.             signal(sig, SIG_DFL);
  308.             kill(getpid(), sig);
  309.             return;
  310.     }
  311.     already_crashed = 1;
  312.  
  313.     dumpcore = 1;
  314.  
  315. #ifndef NO_EMERGENCY_AUTORESTART
  316.         /* Close the X connection and open a new one. This is to avoid messing
  317.          * Xlib because we call to Xlib functions in a signal handler.
  318.          */
  319.         if (dpy)
  320.             XCloseDisplay(dpy);
  321.         dpy = XOpenDisplay("");
  322.         if (dpy) {
  323.         XGrabServer(dpy);
  324.             crashAction = wShowCrashingDialogPanel(sig);
  325.             XCloseDisplay(dpy);
  326.             dpy = NULL;
  327.         } else {
  328.             wsyserror(_("cannot open connection for crashing dialog panel. Aborting."));
  329.             crashAction = WMAbort;
  330.         }
  331.  
  332.         if (crashAction == WMAbort) {
  333.             signal(sig, SIG_DFL);
  334.             kill(getpid(), sig);
  335.             return;
  336.         }
  337.  
  338.         if (crashAction == WMRestart) {
  339.             /* we try to restart Window Maker */
  340.             wwarning(_("trying to restart Window Maker..."));
  341.             Restart(NULL, False);
  342.             /* fallback to alternate window manager then */
  343.         }
  344.  
  345.         wwarning(_("trying to start alternate window manager..."));
  346.  
  347.         Restart(FALLBACK_WINDOWMANAGER, False);
  348.         Restart("fvwm", False);
  349.         Restart("twm", False);
  350.         wfatal(_("failed to start alternate window manager. Aborting."));
  351. #else
  352.         wfatal(_("a fatal error has occured, probably due to a bug. "
  353.                  "Please fill the included BUGFORM and report it."));
  354. #endif /* !NO_EMERGENCY_AUTORESTART */
  355.  
  356.         signal(sig, SIG_DFL);
  357.         kill(getpid(), sig);
  358.         return;
  359.  
  360.     }
  361.  
  362.     wAbort(dumpcore);
  363. }
  364.  
  365.  
  366. static RETSIGTYPE
  367. ignoreSig(int signal)
  368. {
  369.     return;
  370. }
  371.  
  372.  
  373. static RETSIGTYPE
  374. buryChild(int foo)
  375. {
  376.     pid_t pid;
  377.     int status;
  378.     
  379.     /* R.I.P. */
  380.     pid = waitpid(-1, &status, WNOHANG);
  381.     if (pid>0) {
  382.     NotifyDeadProcess(pid, WEXITSTATUS(status));
  383.     /* 
  384.      * Make sure that the kid will be buried even if there are
  385.      * no events in the X event queue
  386.      */
  387.     if (!WDelayedActionSet) {
  388.         WDelayedActionSet = 1;
  389.         WMAddIdleHandler(delayedAction, NULL);
  390.     }
  391.     }
  392. }
  393.  
  394.  
  395. static int
  396. getWorkspaceState(Window root, WWorkspaceState **state)            
  397. {
  398.     Atom type_ret;
  399.     int fmt_ret;    
  400.     unsigned long nitems_ret;
  401.     unsigned long bytes_after_ret;
  402.     CARD32 *data;
  403.  
  404.     if (XGetWindowProperty(dpy, root, _XA_WINDOWMAKER_STATE, 0, 2,
  405.                            True, _XA_WINDOWMAKER_STATE,
  406.                            &type_ret, &fmt_ret, &nitems_ret, &bytes_after_ret,
  407.                            (unsigned char **)&data)!=Success || !data)
  408.       return 0;
  409.  
  410.     *state = malloc(sizeof(WWorkspaceState));
  411.     if (*state) {
  412.     (*state)->flags = data[0];
  413.     (*state)->workspace = data[1];
  414.     }
  415.     XFree(data);
  416.  
  417.     if (*state && type_ret==_XA_WINDOWMAKER_STATE)
  418.       return 1;
  419.     else
  420.       return 0;
  421. }
  422.  
  423.  
  424. static void
  425. getOffendingModifiers()
  426. {
  427.     int i;
  428.     XModifierKeymap *modmap;
  429.     KeyCode nlock, slock;
  430.     static int mask_table[8] = {
  431.     ShiftMask,LockMask,ControlMask,Mod1Mask,
  432.         Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
  433.     };
  434.  
  435.     nlock = XKeysymToKeycode(dpy, XK_Num_Lock);
  436.     slock = XKeysymToKeycode(dpy, XK_Scroll_Lock);
  437.  
  438.     /*
  439.      * Find out the masks for the NumLock and ScrollLock modifiers,
  440.      * so that we can bind the grabs for when they are enabled too.
  441.      */
  442.     modmap = XGetModifierMapping(dpy);
  443.     
  444.     if (modmap!=NULL && modmap->max_keypermod>0) {
  445.     for (i=0; i<8*modmap->max_keypermod; i++) {
  446.         if (modmap->modifiermap[i]==nlock && nlock!=0)
  447.         _NumLockMask = mask_table[i/modmap->max_keypermod];
  448.         else if (modmap->modifiermap[i]==slock && slock!=0)
  449.         _ScrollLockMask = mask_table[i/modmap->max_keypermod];
  450.     }
  451.     }
  452.  
  453.     if (modmap)
  454.     XFreeModifiermap(modmap);
  455. }
  456.  
  457.  
  458.  
  459. #ifdef NUMLOCK_HACK
  460. void 
  461. wHackedGrabKey(int keycode, unsigned int modifiers,
  462.            Window grab_window, Bool owner_events, int pointer_mode,
  463.            int keyboard_mode)
  464. {
  465.     if (modifiers == AnyModifier)
  466.     return;
  467.     
  468.     /* grab all combinations of the modifier with CapsLock, NumLock and
  469.      * ScrollLock. How much memory/CPU does such a monstrosity consume
  470.      * in the server?
  471.      */
  472.     if (_NumLockMask)
  473.     XGrabKey(dpy, keycode, modifiers|_NumLockMask, 
  474.          grab_window, owner_events, pointer_mode, keyboard_mode);
  475.     if (_ScrollLockMask)
  476.     XGrabKey(dpy, keycode, modifiers|_ScrollLockMask,
  477.          grab_window, owner_events, pointer_mode, keyboard_mode);
  478.     if (_NumLockMask && _ScrollLockMask)
  479.     XGrabKey(dpy, keycode, modifiers|_NumLockMask|_ScrollLockMask,
  480.          grab_window, owner_events, pointer_mode, keyboard_mode);
  481.     if (_NumLockMask)
  482.     XGrabKey(dpy, keycode, modifiers|_NumLockMask|LockMask,
  483.          grab_window, owner_events, pointer_mode, keyboard_mode);
  484.     if (_ScrollLockMask)
  485.     XGrabKey(dpy, keycode, modifiers|_ScrollLockMask|LockMask,
  486.          grab_window, owner_events, pointer_mode, keyboard_mode);
  487.     if (_NumLockMask && _ScrollLockMask)
  488.     XGrabKey(dpy, keycode, modifiers|_NumLockMask|_ScrollLockMask|LockMask,
  489.          grab_window, owner_events, pointer_mode, keyboard_mode);
  490.     /* phew, I guess that's all, right? */
  491. }
  492. #endif
  493.  
  494. void 
  495. wHackedGrabButton(unsigned int button, unsigned int modifiers, 
  496.           Window grab_window, Bool owner_events, 
  497.           unsigned int event_mask, int pointer_mode, 
  498.           int keyboard_mode, Window confine_to, Cursor cursor)
  499. {
  500.     XGrabButton(dpy, button, modifiers, grab_window, owner_events,
  501.         event_mask, pointer_mode, keyboard_mode, confine_to, cursor);
  502.  
  503.     if (modifiers==AnyModifier)
  504.     return;
  505.  
  506.     XGrabButton(dpy, button, modifiers|LockMask, grab_window, owner_events,
  507.         event_mask, pointer_mode, keyboard_mode, confine_to, cursor);
  508.     
  509. #ifdef NUMLOCK_HACK    
  510.     /* same as above, but for mouse buttons */
  511.     if (_NumLockMask)
  512.     XGrabButton(dpy, button, modifiers|_NumLockMask,
  513.             grab_window, owner_events, event_mask, pointer_mode,
  514.         keyboard_mode, confine_to, cursor);
  515.     if (_ScrollLockMask)
  516.     XGrabButton(dpy, button, modifiers|_ScrollLockMask,
  517.             grab_window, owner_events, event_mask, pointer_mode,
  518.             keyboard_mode, confine_to, cursor);
  519.     if (_NumLockMask && _ScrollLockMask)
  520.     XGrabButton(dpy, button, modifiers|_ScrollLockMask|_NumLockMask,
  521.             grab_window, owner_events, event_mask, pointer_mode,
  522.             keyboard_mode, confine_to, cursor);
  523.     if (_NumLockMask)
  524.     XGrabButton(dpy, button, modifiers|_NumLockMask|LockMask,
  525.             grab_window, owner_events, event_mask, pointer_mode,
  526.         keyboard_mode, confine_to, cursor);
  527.     if (_ScrollLockMask)
  528.     XGrabButton(dpy, button, modifiers|_ScrollLockMask|LockMask,
  529.             grab_window, owner_events, event_mask, pointer_mode,
  530.             keyboard_mode, confine_to, cursor);
  531.     if (_NumLockMask && _ScrollLockMask)
  532.     XGrabButton(dpy, button, modifiers|_ScrollLockMask|_NumLockMask|LockMask,
  533.             grab_window, owner_events, event_mask, pointer_mode,
  534.             keyboard_mode, confine_to, cursor);
  535. #endif /* NUMLOCK_HACK */
  536. }
  537.  
  538. #ifdef notused
  539. void
  540. wHackedUngrabButton(unsigned int button, unsigned int modifiers, 
  541.             Window grab_window)
  542. {
  543.     XUngrabButton(dpy, button, modifiers|_NumLockMask,
  544.           grab_window);
  545.     XUngrabButton(dpy, button, modifiers|_ScrollLockMask,
  546.           grab_window);
  547.     XUngrabButton(dpy, button, modifiers|_NumLockMask|_ScrollLockMask,
  548.           grab_window);
  549.     XUngrabButton(dpy, button, modifiers|_NumLockMask|LockMask,
  550.           grab_window);
  551.     XUngrabButton(dpy, button, modifiers|_ScrollLockMask|LockMask,
  552.           grab_window);
  553.     XUngrabButton(dpy, button, modifiers|_NumLockMask|_ScrollLockMask|LockMask,
  554.           grab_window);
  555. }
  556. #endif
  557.  
  558.  
  559.  
  560. WScreen*
  561. wScreenWithNumber(int i)
  562. {
  563.     assert(i < wScreenCount);
  564.  
  565.     return wScreen[i];
  566. }
  567.  
  568.  
  569. WScreen*
  570. wScreenForRootWindow(Window window)
  571. {
  572.     int i;
  573.  
  574.     if (wScreenCount==1)
  575.     return wScreen[0];
  576.  
  577.     /*
  578.      * Since the number of heads will probably be small (normally 2),
  579.      * it should be faster to use this than a hash table, because
  580.      * of the overhead.
  581.      */
  582.     for (i=0; i<wScreenCount; i++) {
  583.     if (wScreen[i]->root_win == window) {
  584.         return wScreen[i];
  585.     }
  586.     }
  587.  
  588.     assert("bad_root_window" && 0);
  589.     
  590.     return NULL;
  591. }
  592.  
  593.  
  594. WScreen*
  595. wScreenSearchForRootWindow(Window window)
  596. {
  597.     int i;
  598.  
  599.     if (wScreenCount==1)
  600.     return wScreen[0];
  601.  
  602.     /*
  603.      * Since the number of heads will probably be small (normally 2),
  604.      * it should be faster to use this than a hash table, because
  605.      * of the overhead.
  606.      */
  607.     for (i=0; i<wScreenCount; i++) {
  608.     if (wScreen[i]->root_win == window) {
  609.         return wScreen[i];
  610.     }
  611.     }
  612.     
  613.     return NULL;
  614. }
  615.  
  616.  
  617. WScreen*
  618. wScreenForWindow(Window window)
  619. {
  620.     XWindowAttributes attr;
  621.  
  622.     if (wScreenCount==1)
  623.     return wScreen[0];
  624.  
  625.     if (XGetWindowAttributes(dpy, window, &attr)) {
  626.     return wScreenForRootWindow(attr.root);
  627.     }
  628.     return NULL;
  629. }
  630.  
  631.  
  632. static char *atomNames[] = {
  633.     "WM_STATE", 
  634.     "WM_CHANGE_STATE", 
  635.     "WM_PROTOCOLS", 
  636.     "WM_TAKE_FOCUS", 
  637.     "WM_DELETE_WINDOW", 
  638.     "WM_SAVE_YOURSELF", 
  639.     "WM_CLIENT_LEADER", 
  640.     "WM_COLORMAP_WINDOWS", 
  641.     "WM_COLORMAP_NOTIFY", 
  642.     GNUSTEP_WM_ATTR_NAME, 
  643.     "_WINDOWMAKER_MENU", 
  644.     "_WINDOWMAKER_STATE", 
  645.     "_WINDOWMAKER_WM_PROTOCOLS", 
  646.     GNUSTEP_WM_MINIATURIZE_WINDOW,
  647.     "_WINDOWMAKER_WM_FUNCTION",
  648.     "_WINDOWMAKER_NOTICEBOARD",
  649.     "_WINDOWMAKER_COMMAND",
  650.     "_WINDOWMAKER_ICON_SIZE",
  651.     "_WINDOWMAKER_ICON_TILE",
  652.     GNUSTEP_TITLEBAR_STATE
  653. };
  654.  
  655.  
  656. /*
  657.  *----------------------------------------------------------
  658.  * StartUp--
  659.  *     starts the window manager and setup global data.
  660.  * Called from main() at startup.
  661.  * 
  662.  * Side effects:
  663.  * global data declared in main.c is initialized
  664.  *----------------------------------------------------------
  665.  */
  666. void
  667. StartUp(Bool defaultScreenOnly)
  668. {
  669.     WWorkspaceState *ws_state;
  670.     struct sigaction sig_action;
  671.     int j, max;
  672.     Atom atom[sizeof(atomNames)/sizeof(char*)];
  673.  
  674.     /*
  675.      * Ignore CapsLock in modifiers
  676.      */
  677.     ValidModMask = 0xff & ~LockMask;
  678.  
  679.     getOffendingModifiers();
  680.     /*
  681.      * Ignore NumLock and ScrollLock too
  682.      */
  683.     ValidModMask &= ~(_NumLockMask|_ScrollLockMask);
  684.  
  685.  
  686.     memset(&wKeyBindings, 0, sizeof(wKeyBindings));
  687.  
  688.     wWinContext = XUniqueContext();
  689.     wAppWinContext = XUniqueContext();
  690.     wStackContext = XUniqueContext();
  691.  
  692. /*    _XA_VERSION = XInternAtom(dpy, "VERSION", False);*/
  693.  
  694. #ifdef HAVE_XINTERNATOMS
  695.     XInternAtoms(dpy, atomNames, sizeof(atomNames)/sizeof(char*),
  696.          False, atom);
  697. #else
  698.  
  699.     {
  700.     int i;
  701.     for (i = 0; i < sizeof(atomNames)/sizeof(char*); i++) {
  702.         atom[i] = XInternAtom(dpy, atomNames[i], False);
  703.     }
  704.     }
  705. #endif
  706.     
  707.     _XA_WM_STATE = atom[0];
  708.     _XA_WM_CHANGE_STATE = atom[1];
  709.     _XA_WM_PROTOCOLS = atom[2];
  710.     _XA_WM_TAKE_FOCUS = atom[3];
  711.     _XA_WM_DELETE_WINDOW = atom[4];
  712.     _XA_WM_SAVE_YOURSELF = atom[5];
  713.     _XA_WM_CLIENT_LEADER = atom[6];
  714.     _XA_WM_COLORMAP_WINDOWS = atom[7];
  715.     _XA_WM_COLORMAP_NOTIFY = atom[8];
  716.  
  717.     _XA_GNUSTEP_WM_ATTR = atom[9];
  718.  
  719.     _XA_WINDOWMAKER_MENU = atom[10];
  720.     _XA_WINDOWMAKER_STATE = atom[11];
  721.  
  722.     _XA_WINDOWMAKER_WM_PROTOCOLS = atom[12];
  723.  
  724.     _XA_GNUSTEP_WM_MINIATURIZE_WINDOW = atom[13];
  725.     
  726.     _XA_WINDOWMAKER_WM_FUNCTION = atom[14];
  727.  
  728.     _XA_WINDOWMAKER_NOTICEBOARD = atom[15];
  729.     
  730.     _XA_WINDOWMAKER_COMMAND = atom[16];
  731.  
  732.     _XA_WINDOWMAKER_ICON_SIZE = atom[17];
  733.     _XA_WINDOWMAKER_ICON_TILE = atom[18];
  734.  
  735.     _XA_GNUSTEP_TITLEBAR_STATE = atom[19];
  736.  
  737. #ifdef OFFIX_DND
  738.     _XA_DND_SELECTION = XInternAtom(dpy, "DndSelection", False);
  739.     _XA_DND_PROTOCOL = XInternAtom(dpy, "DndProtocol", False);
  740. #endif
  741. #ifdef XDND
  742.     wXDNDInitializeAtoms();
  743. #endif
  744.  
  745.  
  746.     /* cursors */
  747. #ifdef DEFINABLE_CURSOR
  748.     wCursor[WCUR_NORMAL] = None;
  749. #else
  750.     wCursor[WCUR_NORMAL] = XCreateFontCursor(dpy, XC_left_ptr);    
  751. #endif
  752.     wCursor[WCUR_ROOT] = XCreateFontCursor(dpy, XC_left_ptr);
  753.     wCursor[WCUR_ARROW] = XCreateFontCursor(dpy, XC_top_left_arrow);
  754.     wCursor[WCUR_MOVE] = XCreateFontCursor(dpy, XC_fleur);
  755.     wCursor[WCUR_RESIZE] = XCreateFontCursor(dpy, XC_sizing);
  756.     wCursor[WCUR_TOPLEFTRESIZE] = XCreateFontCursor(dpy, XC_top_left_corner);
  757.     wCursor[WCUR_TOPRIGHTRESIZE] = XCreateFontCursor(dpy, XC_top_right_corner);
  758.     wCursor[WCUR_BOTTOMLEFTRESIZE] = XCreateFontCursor(dpy, XC_bottom_left_corner);
  759.     wCursor[WCUR_BOTTOMRIGHTRESIZE] = XCreateFontCursor(dpy, XC_bottom_right_corner);
  760.     wCursor[WCUR_VERTICALRESIZE] = XCreateFontCursor(dpy, XC_sb_v_double_arrow);
  761.     wCursor[WCUR_HORIZONRESIZE] = XCreateFontCursor(dpy, XC_sb_h_double_arrow);
  762.     wCursor[WCUR_WAIT] = XCreateFontCursor(dpy, XC_watch);
  763.     wCursor[WCUR_QUESTION] = XCreateFontCursor(dpy, XC_question_arrow);
  764.     wCursor[WCUR_TEXT]     = XCreateFontCursor(dpy, XC_xterm); /* odd name???*/
  765.     wCursor[WCUR_SELECT] = XCreateFontCursor(dpy, XC_cross);
  766.     
  767.     /* emergency exit... */
  768.     sig_action.sa_handler = handleSig;
  769.     sigemptyset(&sig_action.sa_mask);
  770.  
  771.     /* Here we don't care about SA_RESTART since these signals will close
  772.      * wmaker anyway.
  773.      * -Dan */
  774.     sig_action.sa_flags = 0;
  775.     sigaction(SIGINT, &sig_action, NULL);
  776.     sigaction(SIGTERM, &sig_action, NULL);
  777.     sigaction(SIGHUP, &sig_action, NULL);
  778.     sigaction(SIGQUIT, &sig_action, NULL);
  779.     sigaction(SIGSEGV, &sig_action, NULL);
  780.     sigaction(SIGBUS, &sig_action, NULL);
  781.     sigaction(SIGFPE, &sig_action, NULL);
  782.     sigaction(SIGABRT, &sig_action, NULL);
  783.  
  784.     /* Here we set SA_RESTART for safety, because SIGUSR1 may not be handled
  785.      * immediately.
  786.      * -Dan */
  787.     sig_action.sa_flags = SA_RESTART;
  788.     sigaction(SIGUSR1, &sig_action, NULL);
  789.  
  790.     /* ignore dead pipe */
  791.     sig_action.sa_handler = ignoreSig;
  792.     sig_action.sa_flags = SA_RESTART;
  793.     sigaction(SIGPIPE, &sig_action, NULL);
  794.  
  795.     /* handle dead children */
  796.     sig_action.sa_handler = buryChild;
  797.     sig_action.sa_flags = SA_NOCLDSTOP|SA_RESTART;
  798.     sigaction(SIGCHLD, &sig_action, NULL);
  799.  
  800.     /* Now we unblock all signals, that may have been blocked by the parent
  801.      * who exec()-ed us. This can happen for example if Window Maker crashes
  802.      * and restarts itself or another window manager from the signal handler.
  803.      * In this case, the new proccess inherits the blocked signal mask and
  804.      * will no longer react to that signal, until unblocked.
  805.      * This is because the signal handler of the proccess who crashed (parent)
  806.      * didn't return, and the signal remained blocked. -Dan
  807.      */
  808.     sigfillset(&sig_action.sa_mask);
  809.     sigprocmask(SIG_UNBLOCK, &sig_action.sa_mask, NULL);
  810.  
  811.     /* handle X shutdowns a such */
  812.     XSetIOErrorHandler(handleXIO);
  813.  
  814.     /* set hook for out event dispatcher in WINGs event dispatcher */
  815.     WMHookEventHandler(DispatchEvent);
  816.  
  817.     /* initialize defaults stuff */
  818.     WDWindowMaker = wDefaultsInitDomain("WindowMaker", True);
  819.     if (!WDWindowMaker->dictionary) {
  820.     wwarning(_("could not read domain \"%s\" from defaults database"),
  821.          "WindowMaker");
  822.     }
  823.  
  824.     /* read defaults that don't change until a restart and are
  825.      * screen independent */
  826.     wReadStaticDefaults(WDWindowMaker ? WDWindowMaker->dictionary : NULL);
  827.  
  828.     /* check sanity of some values */
  829.     if (wPreferences.icon_size < 16) {
  830.     wwarning(_("icon size is configured to %i, but it's too small. Using 16, instead\n"),
  831.          wPreferences.icon_size);
  832.     wPreferences.icon_size = 16;
  833.     }
  834.  
  835.     /* init other domains */
  836.     WDRootMenu = wDefaultsInitDomain("WMRootMenu", False);
  837.     if (!WDRootMenu->dictionary) {
  838.     wwarning(_("could not read domain \"%s\" from defaults database"),
  839.          "WMRootMenu");
  840.     }
  841.  
  842.     WDWindowAttributes = wDefaultsInitDomain("WMWindowAttributes", True);
  843.     if (!WDWindowAttributes->dictionary) {
  844.     wwarning(_("could not read domain \"%s\" from defaults database"),
  845.          "WMWindowAttributes");
  846.     }
  847.  
  848.     XSetErrorHandler((XErrorHandler)catchXError);
  849.  
  850. #ifdef SHAPE
  851.     /* ignore j */
  852.     wShapeSupported = XShapeQueryExtension(dpy, &wShapeEventBase, &j);
  853. #endif
  854.     
  855. #ifdef KEEP_XKB_LOCK_STATUS
  856.     wXkbSupported = XkbQueryExtension(dpy, NULL, &wXkbEventBase, NULL, NULL, NULL);
  857.     if(wPreferences.modelock && !wXkbSupported) {
  858.         wwarning(_("XKB is not supported. KbdModeLock is automatically disabled."));
  859.         wPreferences.modelock = 0;
  860.     }
  861. #endif
  862.  
  863.     if (defaultScreenOnly) {
  864.     max = 1;
  865.     } else {
  866.     max = ScreenCount(dpy);
  867.     }
  868.     wScreen = wmalloc(sizeof(WScreen*)*max);
  869.  
  870.     wScreenCount = 0;
  871.  
  872.     /* manage the screens */
  873.     for (j = 0; j < max; j++) {
  874.     if (defaultScreenOnly || max==1) {
  875.         wScreen[wScreenCount] = wScreenInit(DefaultScreen(dpy));
  876.         if (!wScreen[wScreenCount]) {
  877.         wfatal(_("it seems that there is already a window manager running"));
  878.         Exit(1);
  879.         }
  880.     } else {
  881.         wScreen[wScreenCount] = wScreenInit(j);
  882.         if (!wScreen[wScreenCount]) {
  883.         wwarning(_("could not manage screen %i"), j);
  884.         continue;
  885.         }
  886.     }
  887.     wScreenCount++;
  888.     }
  889.  
  890.     /* initialize/restore state for the screens */
  891.     for (j = 0; j < wScreenCount; j++) {
  892.     /* restore workspace state */
  893.     if (!getWorkspaceState(wScreen[j]->root_win, &ws_state)) {
  894.         ws_state = NULL;
  895.     }
  896.  
  897.     wScreenRestoreState(wScreen[j]);
  898.  
  899.     /* manage all windows that were already here before us */
  900.     if (!wPreferences.flags.nodock && wScreen[j]->dock)
  901.         wScreen[j]->last_dock = wScreen[j]->dock;
  902.     
  903.     manageAllWindows(wScreen[j]);
  904.     
  905.     /* restore saved menus */
  906.     wMenuRestoreState(wScreen[j]);
  907.     
  908.     /* If we're not restarting restore session */
  909.     if (ws_state == NULL && !wPreferences.flags.norestore)
  910.         wSessionRestoreState(wScreen[j]);
  911.     
  912.     if (!wPreferences.flags.noautolaunch) {
  913.         /* auto-launch apps */
  914.         if (!wPreferences.flags.nodock && wScreen[j]->dock) {
  915.         wScreen[j]->last_dock = wScreen[j]->dock;
  916.         wDockDoAutoLaunch(wScreen[j]->dock, 0);
  917.         }
  918.         /* auto-launch apps in clip */
  919.         if (!wPreferences.flags.noclip) {
  920.         int i;
  921.         for(i=0; i<wScreen[j]->workspace_count; i++) {
  922.             if (wScreen[j]->workspaces[i]->clip) {
  923.             wScreen[j]->last_dock = wScreen[j]->workspaces[i]->clip;
  924.             wDockDoAutoLaunch(wScreen[j]->workspaces[i]->clip, i);
  925.             }
  926.         }
  927.         }
  928.     }
  929.  
  930.     /* go to workspace where we were before restart */
  931.     if (ws_state) { 
  932.         wWorkspaceForceChange(wScreen[j], ws_state->workspace);
  933.         free(ws_state);
  934.     } else {
  935.         wSessionRestoreLastWorkspace(wScreen[j]);
  936.     }
  937.  
  938. #ifdef KWM_HINTS
  939.     wKWMSetInitializedHint(wScreen[j]);
  940. #endif
  941.     }
  942.     
  943.     if (wScreenCount == 0) {
  944.     wfatal(_("could not manage any screen"));
  945.     Exit(1);
  946.     }
  947.  
  948.     if (!wPreferences.flags.noupdates) {
  949.     /* setup defaults file polling */
  950.     WMAddTimerHandler(3000, wDefaultsCheckDomains, NULL);
  951.     }
  952. }
  953.  
  954.  
  955.  
  956.  
  957. static Bool
  958. windowInList(Window window, Window *list, int count)
  959. {
  960.     for (; count>=0; count--) {
  961.     if (window == list[count])
  962.         return True;
  963.     }
  964.     return False;
  965. }
  966.  
  967. /*
  968.  *-----------------------------------------------------------------------
  969.  * manageAllWindows--
  970.  *     Manages all windows in the screen.
  971.  * 
  972.  * Notes:
  973.  *     Called when the wm is being started.
  974.  *    No events can be processed while the windows are being
  975.  * reparented/managed. 
  976.  *----------------------------------------------------------------------- 
  977.  */
  978. static void
  979. manageAllWindows(WScreen *scr)
  980. {
  981.     Window root, parent;
  982.     Window *children;
  983.     unsigned int nchildren;
  984.     unsigned int i, j;
  985.     WWindow *wwin;
  986.  
  987.     XGrabServer(dpy);
  988.     XQueryTree(dpy, scr->root_win, &root, &parent, &children, &nchildren);
  989.  
  990.     scr->flags.startup = 1;
  991.  
  992.     /* first remove all icon windows */
  993.     for (i = 0; i < nchildren; i++) {
  994.     XWMHints *wmhints;
  995.  
  996.     if (children[i]==None) 
  997.         continue;
  998.  
  999.         wmhints = XGetWMHints(dpy, children[i]);
  1000.     if (wmhints && (wmhints->flags & IconWindowHint)) {
  1001.         for (j = 0; j < nchildren; j++)  {
  1002.         if (children[j] == wmhints->icon_window) {
  1003.             XFree(wmhints);
  1004.             wmhints = NULL;
  1005.             children[j] = None;
  1006.             break;
  1007.         }
  1008.         }
  1009.     }
  1010.     if (wmhints) {
  1011.         XFree(wmhints);
  1012.     }
  1013.     }
  1014.  
  1015.  
  1016.     for (i = 0; i < nchildren; i++) {
  1017.     if (children[i] == None)
  1018.         continue;
  1019.  
  1020. #ifdef KWM_HINTS
  1021.     wKWMCheckModule(scr, children[i]);
  1022. #endif
  1023.     wwin = wManageWindow(scr, children[i]);
  1024.     if (wwin) {
  1025.         /* apply states got from WSavedState */
  1026.         /* shaded + minimized is not restored correctly */
  1027.         if (wwin->flags.shaded) {
  1028.         wwin->flags.shaded = 0;
  1029.         wShadeWindow(wwin);
  1030.         }
  1031.         if (wwin->flags.miniaturized
  1032.         && (wwin->transient_for == None
  1033.             || wwin->transient_for == scr->root_win
  1034.             || !windowInList(wwin->transient_for, children, 
  1035.                      nchildren))) {
  1036.  
  1037.         wwin->flags.skip_next_animation = 1;
  1038.         wwin->flags.miniaturized = 0;
  1039.         wIconifyWindow(wwin);
  1040.         } else {
  1041.         wClientSetState(wwin, NormalState, None);
  1042.         }
  1043.     }
  1044.     }
  1045.     XUngrabServer(dpy);
  1046.  
  1047.     /* hide apps */
  1048.     wwin = scr->focused_window;
  1049.     while (wwin) {
  1050.     if (wwin->flags.hidden) {
  1051.         WApplication *wapp = wApplicationOf(wwin->main_window);
  1052.  
  1053.         if (wapp) {
  1054.         wwin->flags.hidden = 0;
  1055.         wHideApplication(wapp);
  1056.         } else {
  1057.         wwin->flags.hidden = 0;
  1058.         }
  1059.     }
  1060.     wwin = wwin->prev;
  1061.     }
  1062.  
  1063.     XFree(children);
  1064.     scr->flags.startup = 0;
  1065.     scr->flags.startup2 = 1;
  1066.  
  1067.     while (XPending(dpy)) {
  1068.     XEvent ev;
  1069.     WMNextEvent(dpy, &ev);
  1070.     WMHandleEvent(&ev);
  1071.     }
  1072.     wWorkspaceForceChange(scr, 0);
  1073.     if (!wPreferences.flags.noclip)
  1074.         wDockShowIcons(scr->workspaces[scr->current_workspace]->clip);
  1075.     scr->flags.startup2 = 0;
  1076. }
  1077.  
  1078.  
  1079.  
  1080.